/*
* Fastjs official plugin
*
* About this plugin:
*   Version: v1.0.1
*   Plugin: ajax.fs.js
*   Author: Fastjs Team
*   Contact-Us: xiaodong@indouyin.cn
*/

const Ajax = {
    newVersionCheck: false,
    log: true,
    encode: true,
    error: {
        checkTimeout: true,
        urlNotSecurity: true
    },
    hooks: {
        beforeSetup(ajax) {
        },
        beforeSend(ajax) {
        },
        send(ajax) {
        },
        beforeUpdate(ajax, status) {
        },
        update(ajax, status) {
        }
    }
}

class ajax {
    /*
     * @string url
     * @object data
     * @function callback
     * @integer timeout
     * @object datatype
     * @string datatype
     */
    constructor(url, data = {}, callback = () => {
    }, failed = () => {
    }, timeout = 5000, header = {}, datatype = "auto", async = true) {
        switch (timeout) {
            case void 0:
                timeout = 5000
                break
            case timeout < 1000:
                if (Ajax.error.checkTimeout)
                    fastjs.qualityOutput("Class.ajax.__constructor__", "Illogical timeout")
        }
        switch (datatype) {
            case !["json", "text", "auto"].search(datatype):
                datatype = "auto"
                fastjs.throwError("Class.ajax.__constructor__", "Unknown type given of datatype")
        }
        this.url = url
        this.data = data
        this.callback = callback
        this.timeout = timeout
        this.header = header
        this.datatype = datatype
        this.async = async
        this.failed = failed
    }

    send(url, data, callback, method) {
        if (Ajax.hooks.beforeSetup(this) === false) return false
        if (!url) {
            if (!this.url) {
                fastjs.throwCrashError("Class.ajax.%s%->send".push(method, "%s%"), "Empty data given of url, but it should had something")
                return void 0
            }
            url = this.url
        }
        let timeout = this.timeout
        callback = callback ? callback : this.callback
        data = data ? data : this.data
        let datatype = this.datatype
        let info = ""
        Object.entries(data).forEach((e, key) => {
            if (Ajax.encode)
                e[1] = encodeURIComponent(e[1])
            info += key ? `&${e[0]}=${e[1]}` : `${e[0]}=${e[1]}`
        })

        if (url.search("http://") !== false)
            if (FASTJS_CONFIG.error.urlNotSecurity)
                fastjs.throwSmallError(`Class.ajax.${method}->send`, "The url given is not secure")

        // Create XMLHttpRequest
        let xhr = new XMLHttpRequest()
        xhr.responseType = "text"
        if (datatype === "json") {
            xhr.responseType = "json"
        }
        xhr.timeout = timeout
        this.xhr = xhr
        if (Ajax.hooks.beforeSend(this) === false) return false
        // Timeout function
        xhr.sendTimeout = setTimeout(() => {
            if (Ajax.hooks.beforeUpdate(this, false) === false) return false
            if (Ajax.log)
                console.log(`[Fastjs ajax] ajaxRequest to url ${url} is failed`)
            if (typeof this.failed === "function")
                this.failed("!failed", xhr.status)
            this.result = "!failed"
            if (Ajax.hooks.update(this, false) === false) return false
        }, timeout)
        xhr.open(method, method === "get" ? url + (info.length > 0 ? "?" : "") + info : url, this.async)
        xhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded")
        xhr.responseType = datatype === "json" ? "json" : "text"
        Object.entries(this.header).forEach((e) => {
            xhr.setRequestHeader(e[0], e[1])
        })
        // Ajax onload
        xhr.onload = () => {
            // Clear timeout function
            clearTimeout(xhr.sendTimeout)
            let response = xhr.response
            if (datatype === "auto") {
                try {
                    // Try change to json data
                    response = JSON.parse(response)
                } catch (e) {
                }
            }
            this.result = response
            this.status = xhr.status
            if (Ajax.hooks.beforeUpdate(this, true) === false) return false
            // Ajax log
            if (Ajax.log) {
                console.log("[Fastjs ajax] ajaxRequest to url %s is success".replace("%s", url))
            }
            // Callback function
            if (callback && typeof callback == "function") {
                callback(response, 200)
            }
            if (Ajax.hooks.update(this, true) === false) return false
        }
        xhr.send(method === "post" ? info : null)
        this.xhr = xhr
        return !Ajax.hooks.send(this) === false;

    }

    /*
     * @string url
     * @object data
     * @function callback
     */
    post(url, data, callback) {
        this.send(url, data, callback, "post")
    }

    /*
     * @string url
     * @object data
     * @function callback
     */
    get(url, data, callback) {
        this.send(url, data, callback, "get")
    }
}

if (Ajax.newVersionCheck) {
    let versionCheck = new ajax("https://fastjs.com.cn/lastVersion.php")
    versionCheck.callback = result => {
        if (result.version !== FASTJS_CONFIG.version && result !== "!failed") {
            console.log("[Fastjs] Fastjs have a new version %s% can update, go to https://fastjs.com.cn/ to get more info".push(result.version, "%s%"))
        }
    }
    versionCheck.get()
}